package com.example.coursehub.service.impl;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import com.example.coursehub.entity.*;
import com.example.coursehub.repository.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.coursehub.dto.*;
import com.example.coursehub.service.ExerciseService;

@Service
@Transactional
public class ExerciseServiceImpl implements ExerciseService {
    private final ExerciseRepository exerciseRepository;
    private final ExerciseQuestionRepository exerciseQuestionRepository;
    private final FavoriteQuestionBankRepository favoriteQuestionBankRepository;
    private final FavoriteQuestionBankQuestionRepository favoriteQuestionBankQuestionRepository;
    private final WrongQuestionBankRepository wrongQuestionBankRepository;
    private final WrongQuestionBankQuestionRepository wrongQuestionBankQuestionRepository;
    private final StudentExerciseRepository studentExerciseRepository;
    private final StudentQuestionAnswerRepository studentQuestionAnswerRepository;
    private final QuestionRepository questionRepository;
    private final CourseRepository courseRepository;
    private final UserRepository userRepository;
    private final ClassesRepository classesRepository;
    private final ClassesStudentRepository classesStudentRepository;
    private final CourseQuestionBankRepository courseQuestionBankRepository;
    private final CourseQuestionBankQuestionRepository courseQuestionBankQuestionRepository;
    private final ClassesTeacherRepository classesTeacherRepository;
    private final CourseStudentRepository courseStudentRepository;
    private final CourseTeacherRepository courseTeacherRepository;
    public ExerciseServiceImpl(ExerciseRepository exerciseRepository,
                               ExerciseQuestionRepository exerciseQuestionRepository,
                               FavoriteQuestionBankRepository favoriteQuestionBankRepository,
                               FavoriteQuestionBankQuestionRepository favoriteQuestionBankQuestionRepository,
                               WrongQuestionBankRepository wrongQuestionBankRepository,
                               WrongQuestionBankQuestionRepository wrongQuestionBankQuestionRepository,
                               StudentExerciseRepository studentExerciseRepository,
                               StudentQuestionAnswerRepository studentQuestionAnswerRepository,
                               QuestionRepository questionRepository,
                               CourseRepository courseRepository,
                               UserRepository userRepository,
                               ClassesRepository classesRepository,
                               ClassesStudentRepository classesStudentRepository, CourseQuestionBankRepository courseQuestionBankRepository, CourseQuestionBankQuestionRepository courseQuestionBankQuestionRepository, ClassesTeacherRepository classesTeacherRepository, CourseStudentRepository courseStudentRepository, CourseTeacherRepository courseTeacherRepository) {
        this.exerciseRepository = exerciseRepository;
        this.exerciseQuestionRepository = exerciseQuestionRepository;
        this.favoriteQuestionBankRepository = favoriteQuestionBankRepository;
        this.favoriteQuestionBankQuestionRepository = favoriteQuestionBankQuestionRepository;
        this.wrongQuestionBankRepository = wrongQuestionBankRepository;
        this.wrongQuestionBankQuestionRepository = wrongQuestionBankQuestionRepository;
        this.studentExerciseRepository = studentExerciseRepository;
        this.studentQuestionAnswerRepository = studentQuestionAnswerRepository;
        this.questionRepository = questionRepository;
        this.courseRepository = courseRepository;
        this.userRepository = userRepository;
        this.classesRepository = classesRepository;
        this.classesStudentRepository = classesStudentRepository;
        this.courseQuestionBankRepository = courseQuestionBankRepository;
        this.courseQuestionBankQuestionRepository = courseQuestionBankQuestionRepository;
        this.classesTeacherRepository = classesTeacherRepository;
        this.courseStudentRepository = courseStudentRepository;
        this.courseTeacherRepository = courseTeacherRepository;
    };
    @Override
    public Exercise createExercise(Exercise exercise) {
        // 确保练习开始时间和截止时间正确设置
        exercise.setExerciseStartTime(
                exercise.getExerciseStartTime() != null ? exercise.getExerciseStartTime()
                        : LocalDateTime.now());
        return exerciseRepository.save(exercise);
    }

    @Override
    public void deleteExercise(String exerciseId) {
        exerciseRepository.findById(exerciseId).orElseThrow(
                () -> new IllegalArgumentException("练习不存在，ID: " + exerciseId));
        exerciseQuestionRepository.deleteByExercise_ExerciseId(exerciseId);
        exerciseRepository.deleteById(exerciseId);
    }

    @Override
    public Exercise getExerciseById(String exerciseId) {
        return exerciseRepository.findById(exerciseId)
                .orElseThrow(() -> new IllegalArgumentException("练习不存在，ID: " + exerciseId));
    }

    @Override
    public List<Exercise> getUnfinishedExercises(String courseId, String userId) {
        // 1. 查询学生在指定课程下所有未提交（unsubmitted）的练习记录
        List<StudentExercise> unfinishedStudentExercises = studentExerciseRepository
                .findByUserIdAndStateAndCourseId(userId, "unsubmitted", courseId);

        // 2. 提取练习对象列表
        return unfinishedStudentExercises.stream()
                .map(StudentExercise::getExercise)
                .collect(Collectors.toList());
    }

    @Override
    public List<Exercise> getFinishedExercises(String courseId, String userId) {
        // 1. 查询学生在指定课程下已提交（submitted）或已批改（marked）的练习记录
        List<StudentExercise> finishedStudentExercises = studentExerciseRepository
                .findByUserIdAndStateInAndCourseId(userId, List.of("submitted", "marked"), courseId);

        // 2. 提取练习对象列表
        return finishedStudentExercises.stream()
                .map(StudentExercise::getExercise)
                .collect(Collectors.toList());
    }
    @Override
    public ExerciseDetailDTO getExerciseDetail(String exerciseId, String userId) {
        // 1. 查询练习基本信息
        Exercise exercise = exerciseRepository.findById(exerciseId)
                .orElseThrow(() -> new IllegalArgumentException("练习不存在，ID: " + exerciseId));

        // 2. 查询学生练习记录（状态、得分、是否可重复提交）
        StudentExercise studentExercise = studentExerciseRepository.findByUser_UserIdAndExercise_ExerciseId(userId, exerciseId)
                .orElse(new StudentExercise()); // 若不存在，返回空记录（未提交状态）

        // 3. 查询练习下的所有题目（通过中间表 ExerciseQuestion）
        List<ExerciseQuestion> exerciseQuestions = exerciseQuestionRepository.findByExercise_ExerciseId(exerciseId);
        List<String> questionIds = exerciseQuestions.stream()
                .map(eq -> eq.getQuestionId())
                .collect(Collectors.toList());
        List<Question> questions = questionRepository.findAllById(questionIds);

        // 4. 查询学生对每个题目的答案（若已提交）
        List<StudentQuestionAnswer> studentAnswers = studentQuestionAnswerRepository.findByExercise_ExerciseIdAndUser_UserId(exerciseId, userId);

        // 5. 组装题目与答案的关联关系
        List<QuestionWithAnswerDTO> questionWithAnswerList = questions.stream()
                .map(question -> {
                    StudentQuestionAnswer answer = studentAnswers.stream()
                            .filter(a -> a.getQuestion().getQuestionId().equals(question.getQuestionId()))
                            .findFirst()
                            .orElse(null);
                    return new QuestionWithAnswerDTO(question, answer);
                })
                .collect(Collectors.toList());

        // 6. 封装成 DTO 返回
        return new ExerciseDetailDTO(exercise, studentExercise, questionWithAnswerList);
    }

    @Override
    public List<Question> getFavoriteQuestionBank(String userId, String courseId) {
        System.out.println("到达Service层 " + userId + " "+  courseId);
        // 查询用户在课程中的收藏题库
        FavoriteQuestionBank favoriteBank = favoriteQuestionBankRepository.findByUser_UserIdAndCourse_CourseId(
                userId, courseId).orElseThrow(() -> new IllegalArgumentException("无收藏题库"));

        List<String> questionIds = favoriteQuestionBankQuestionRepository
                .findByFavoriteQuestionBank_FavoriteQuestionBankId(favoriteBank.getFavoriteQuestionBankId())
                .stream()
                .map(FavoriteQuestionBankQuestion::getQuestionId)
                .collect(Collectors.toList());
//                System.out.println("成功找到错题库 接下来返回" + questionIds);
        List<Question> questions = questionRepository.findAllById(questionIds);

        // 打印每个题目的信息
        if (questions.isEmpty()) {
            System.out.println("查询结果为空：未找到任何题目");
        } else {
            System.out.println("查询到以下题目信息：" + questions);
            for (Question question : questions) {
                System.out.println("题目ID: " + question.getQuestionId() +
                        ", 类型: " + question.getType() +
                        ", 分值: " + question.getQuestionScore());
            }
        }

        return questions;
    }

    @Override
    public List<Question> getWrongQuestionBank(String userId, String courseId) {
        // 查询用户在课程中的错题题库
        WrongQuestionBank wrongBank = wrongQuestionBankRepository.findByUser_UserIdAndCourse_CourseId(
                userId, courseId).orElseThrow(() -> new IllegalArgumentException("无错题题库"));

        List<String> questionIds = wrongQuestionBankQuestionRepository
                .findByWrongQuestionBank_WrongQuestionBankId(wrongBank.getWrongQuestionBankId())
                .stream()
                .map(WrongQuestionBankQuestion::getQuestionId)
                .collect(Collectors.toList());

        return questionRepository.findAllById(questionIds);
    }
    @Override
    @Transactional
    public void submittedExercise(StudentExercise studentExercise, List<StudentQuestionAnswer> studentQuestionAnswers) {
        if (studentExercise == null || studentExercise.getId() == null) {
            throw new IllegalArgumentException("学生练习记录或其主键不能为空");
        }
        if (studentQuestionAnswers == null || studentQuestionAnswers.isEmpty()) {
            throw new IllegalArgumentException("题目答案列表不能为空");
        }

        try {
            // 获取练习和用户实体
            Exercise exercise = exerciseRepository.findById(studentExercise.getId().getExerciseId())
                    .orElseThrow(() -> new IllegalArgumentException("练习不存在"));
            User user = userRepository.findById(studentExercise.getId().getUserId())
                    .orElseThrow(() -> new IllegalArgumentException("用户不存在"));

            // 设置学生练习的关联和默认得分
            studentExercise.setUser(user);
            studentExercise.setExercise(exercise);
            studentExercise.setStudentScore(0);
            studentExerciseRepository.save(studentExercise);

            // 处理题目答案
            studentQuestionAnswers.forEach(answer -> {
                // 设置关联实体
                answer.setUser(user);
                answer.setQuestion(questionRepository.findById(answer.getId().getQuestionId())
                        .orElseThrow(() -> new IllegalArgumentException("题目不存在")));
                answer.setExercise(exercise);

                // 校验答案内容非空（可选）
                if (answer.getStudentAnswer() == null || answer.getStudentAnswer().trim().isEmpty()) {
                    throw new IllegalArgumentException("题目答案内容不能为空，题目 ID: " + answer.getId().getQuestionId());
                }

                // 自动填充复合主键（若前端未传递完整主键）
                answer.getId().setUserId(user.getUserId());
                answer.getId().setExerciseId(exercise.getExerciseId());
            });

            studentQuestionAnswerRepository.saveAll(studentQuestionAnswers);
        } catch (Exception e) {
            throw new RuntimeException("提交练习失败: " + e.getMessage(), e);
        }
    }

    @Override
    public void addFavoriteQuestion(String userId, String courseId, String questionId) {
        // 1. 校验题目是否存在
        questionRepository.findById(questionId).orElseThrow(
                () -> new IllegalArgumentException("题目不存在，ID: " + questionId)
        );

        // 2. 查询或创建用户在该课程的收藏题库
        FavoriteQuestionBank favoriteBank = favoriteQuestionBankRepository
                .findByUser_UserIdAndCourse_CourseId(userId, courseId) // 通过关联实体的ID查询
                .orElseGet(() -> {
                    // 查询 User 和 Course 实体（必须存在，否则抛出异常）
                    User user = userRepository.findById(userId).orElseThrow(
                            () -> new IllegalArgumentException("用户不存在，ID: " + userId)
                    );
                    Course course = courseRepository.findById(courseId).orElseThrow(
                            () -> new IllegalArgumentException("课程不存在，ID: " + courseId)
                    );

                    // 使用构造函数创建新收藏题库（传入实体对象，而非ID字符串）
                    FavoriteQuestionBank newBank = new FavoriteQuestionBank(
                            null, // 主键可由数据库自增生成（若为null，JPA会处理）
                            user,
                            course
                    );

                    // 保存到数据库
                    return favoriteQuestionBankRepository.save(newBank);
                });

        // 3. 检查题目是否已被收藏（避免重复添加）
        if (favoriteQuestionBankQuestionRepository.existsByFavoriteQuestionBank_FavoriteQuestionBankIdAndQuestion_QuestionId(
                favoriteBank.getFavoriteQuestionBankId(),
                questionId
        )) {
            throw new IllegalArgumentException("题目已被收藏，ID: " + questionId);
        }
        // 获取收藏题库的 ID 和题目 ID，构造联合主键
        String favoriteBankId = favoriteBank.getFavoriteQuestionBankId();
        // 创建联合主键对象
        FavoriteQuestionBankQuestionId id = new FavoriteQuestionBankQuestionId(favoriteBankId, questionId);

        // 使用构造器创建 FavoriteQuestionBankQuestion 实例（传入主键和关联实体）
        FavoriteQuestionBankQuestion favoriteQuestion = new FavoriteQuestionBankQuestion(
                id,
                favoriteBank, // 关联的收藏题库实体
                questionRepository.findById(questionId).orElseThrow() // 查询并传入题目实体
        );

        // 保存关联记录（JPA 会自动处理实体关系和主键）
        favoriteQuestionBankQuestionRepository.save(favoriteQuestion);

    }

        @Override
                public List<Exercise> getAllCourseExercises(String courseId) {
                // 1. 查询课程对应的所有班级（通过 courseId 关联 classes 表）
                List<Classes> classesList = classesRepository.findByCourseCourseId(courseId);

                // 2. 提取班级 ID 列表（若没有班级，返回空列表）
                List<String> classIds = classesList.stream()
                        .map(Classes::getClassesId)
                        .collect(Collectors.toList());

                // 3. 根据班级 ID 列表查询所有练习（使用 IN 条件批量查询）
                return exerciseRepository.findByClassesIdIn(classIds);
        }

        @Override
        public List<Exercise> getAllClassExercises(String classId) {
            return exerciseRepository.findByClasses_ClassesId(classId);
        }

        @Override
        public List<StudentExercise> getAllStudentExercise(String exerciseId) {
                // 调用 StudentExerciseRepository 中根据练习 ID 查询的方法
                return studentExerciseRepository.findByExercise_ExerciseId(exerciseId);
        }
        @Override
        public List<StudentQuestionAnswer> getAllStudentQuestionAnswer(String exerciseId, String studentId) {
                // 调用 Repository 根据练习 ID 和学生 ID 查询答案列表
                return studentQuestionAnswerRepository.findByExercise_ExerciseIdAndUser_UserId(exerciseId, studentId);
        }

    @Override
    public void removeFavoriteQuestion(String userId, String courseId, String questionId) {
        // 1. 查询用户在该课程的收藏题库（若不存在则抛出异常）
        FavoriteQuestionBank favoriteBank = favoriteQuestionBankRepository
                .findByUser_UserIdAndCourse_CourseId(userId, courseId)
                .orElseThrow(() -> new IllegalArgumentException("用户在该课程下无收藏题库，userId: " + userId + ", courseId: " + courseId));

        // 2. 查询题目在收藏题库中的关联记录（若不存在则抛出异常）
        FavoriteQuestionBankQuestion favoriteQuestion = favoriteQuestionBankQuestionRepository
                .findByFavoriteQuestionBank_FavoriteQuestionBankIdAndQuestion_QuestionId(favoriteBank.getFavoriteQuestionBankId(), questionId)
                .orElseThrow(() -> new IllegalArgumentException("题目未被收藏，userId: " + userId + ", courseId: " + courseId + ", questionId: " + questionId));

        // 3. 删除关联记录（事务自动回滚，若删除失败）
        favoriteQuestionBankQuestionRepository.delete(favoriteQuestion);
    }
    @Override
    public List<Question> getExerciseQuestions(String exerciseId) {
        // 1. 查询练习是否存在（不存在则抛出异常）
        Exercise exercise = exerciseRepository.findById(exerciseId)
                .orElseThrow(() -> new IllegalArgumentException("练习不存在，ID: " + exerciseId));

        // 2. 通过 ExerciseQuestion 关联表查询练习下的所有题目
        List<ExerciseQuestion> exerciseQuestions = exerciseQuestionRepository.findByExercise_ExerciseId(exerciseId);

        // 3. 提取题目 ID 列表
        List<String> questionIds = exerciseQuestions.stream()
                .map(ExerciseQuestion::getQuestionId)
                .collect(Collectors.toList());

        // 4. 批量查询题目详情
        return questionRepository.findAllById(questionIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Exercise createExerciseWithQuestions(ExerciseCreateDTO dto) {
        if (dto == null || dto.getExercise() == null || dto.getQuestions().isEmpty() || dto.getExerciseQuestions().isEmpty()) {
            throw new IllegalArgumentException("核心数据不能为空");
        }

        Exercise savedExercise = saveExerciseAndQuestions(dto);
        createStudentExercisesForClass(savedExercise); // 可能在此处抛出异常
        return savedExercise;
    }

    private Exercise saveExerciseAndQuestions(ExerciseCreateDTO dto) {
        Exercise exercise = dto.getExercise();
        validateExercise(exercise);

        // 确保班级存在
        Classes classes = classesRepository.findById(exercise.getClasses().getClassesId())
                .orElseThrow(() -> new IllegalArgumentException("班级不存在，ID: " + exercise.getClasses().getClassesId()));
        exercise.setClasses(classes); // 明确设置关联实体

        Exercise savedExercise = exerciseRepository.save(exercise);
        List<Question> savedQuestions = questionRepository.saveAll(dto.getQuestions());
        validateAndSaveExerciseQuestions(savedExercise, savedQuestions, dto.getExerciseQuestions());
        return savedExercise;
    }

    private void createStudentExercisesForClass(Exercise exercise) {
        String classesId = exercise.getClasses().getClassesId();
        // 1. 检查班级是否存在（防御性编程）
        Classes classes = classesRepository.findById(classesId)
                .orElseThrow(() -> new IllegalArgumentException("班级不存在，ID: " + classesId));

        // 2. 查询班级学生（使用正确的关联路径）
        List<ClassesStudent> classStudents = classesStudentRepository.findByClasses_ClassesId(classesId);

        if (classStudents.isEmpty()) {
            return;
        }

        // 3. 批量创建学生练习记录（确保关联实体非空）
        List<StudentExercise> studentExercises = classStudents.stream()
                .map(classStudent -> {
                    // 检查学生是否存在
                    if (classStudent.getUser() == null || classStudent.getUser().getUserId() == null) {
                        throw new IllegalArgumentException("学生用户信息缺失，班级学生记录: " + classStudent);
                    }

                    StudentExercise studentExercise = new StudentExercise();
                    StudentExerciseId id = new StudentExerciseId();
                    id.setUserId(classStudent.getUser().getUserId()); // 使用关联实体的用户ID
                    id.setExerciseId(exercise.getExerciseId());

                    studentExercise.setId(id);
                    studentExercise.setUser(classStudent.getUser()); // 必须关联存在的用户实体
                    studentExercise.setExercise(exercise);
                    studentExercise.setState("unsubmitted"); // 确保状态非空
                    studentExercise.setStudentScore(0); // 确保分数非空

                    return studentExercise;
                })
                .collect(Collectors.toList());

        // 4. 批量保存（添加事务和异常处理）
        try {
            studentExerciseRepository.saveAll(studentExercises);
        } catch (Exception e) {
            throw new RuntimeException("批量保存学生练习记录失败: " + e.getMessage(), e);
        }
    }

    // 校验练习字段的辅助方法
    private void validateExercise(Exercise exercise) {
        // 校验主键 exerciseId 非空（根据实体类定义，exerciseId 是必填字段）
        if (exercise.getExerciseId() == null || exercise.getExerciseId().trim().isEmpty()) {
            throw new IllegalArgumentException("练习ID（exerciseId）不能为空");
        }
        // 校验练习名称非空
        if (exercise.getExerciseName() == null || exercise.getExerciseName().trim().isEmpty()) {
            throw new IllegalArgumentException("练习名称（exerciseName）不能为空");
        }
        // 校验截止时间非空
        if (exercise.getExerciseDeadline() == null) {
            throw new IllegalArgumentException("练习截止时间（exerciseDeadline）不能为空");
        }
        // 校验开始时间非空（若为空，使用当前时间填充）
        if (exercise.getExerciseStartTime() == null) {
            exercise.setExerciseStartTime(LocalDateTime.now());
        }
        // 校验班级关联非空（根据实体类定义，classes 是 @ManyToOne 且 optional=false）
        if (exercise.getClasses() == null || exercise.getClasses().getClassesId() == null) {
            throw new IllegalArgumentException("练习关联的班级（classes）不能为空");
        }
        // 校验班级是否存在（可选，根据业务需求）
        Classes classes = classesRepository.findById(exercise.getClasses().getClassesId())
                .orElseThrow(() -> new IllegalArgumentException("班级不存在，ID: " + exercise.getClasses().getClassesId()));
        exercise.setClasses(classes); // 确保关联的是数据库中的实体对象
    }

    // 校验题目列表的辅助方法
    private void validateQuestions(List<Question> questions) {
        for (Question question : questions) {
            // 校验题目ID非空
            if (question.getQuestionId() == null || question.getQuestionId().trim().isEmpty()) {
                throw new IllegalArgumentException("题目ID（questionId）不能为空");
            }
            // 校验题目内容非空
            if (question.getQuestionContent() == null || question.getQuestionContent().trim().isEmpty()) {
                throw new IllegalArgumentException("题目内容（questionContent）不能为空");
            }
            // 校验题目答案非空
            if (question.getQuestionAnswer() == null || question.getQuestionAnswer().trim().isEmpty()) {
                throw new IllegalArgumentException("题目答案（questionAnswer）不能为空");
            }
            // 校验题目分数非负（根据实体类定义，questionScore 是 unsigned int）
            if (question.getQuestionScore() == null || question.getQuestionScore() < 0) {
                throw new IllegalArgumentException("题目分数（questionScore）必须为非负整数");
            }
        }
    }

    // 校验练习-题目关联的辅助方法
    private void validateAndSaveExerciseQuestions(Exercise savedExercise,
                                                  List<Question> savedQuestions,
                                                  List<ExerciseQuestion> exerciseQuestions) {
        // 收集所有已保存的题目ID（用于校验关联关系）
        List<String> savedQuestionIds = savedQuestions.stream()
                .map(Question::getQuestionId)
                .collect(Collectors.toList());

        for (ExerciseQuestion eq : exerciseQuestions) {
            // 1. 校验关联主键非空
            ExerciseQuestionId eqId = eq.getId();
            if (eqId == null) {
                throw new IllegalArgumentException("练习-题目关联主键（ExerciseQuestionId）不能为空");
            }
            if (eqId.getExerciseId() == null || eqId.getQuestionId() == null) {
                throw new IllegalArgumentException("练习-题目关联的exerciseId或questionId不能为空");
            }

            // 2. 校验关联的exerciseId与已保存的练习ID一致
            if (!eqId.getExerciseId().equals(savedExercise.getExerciseId())) {
                throw new IllegalArgumentException("练习-题目关联的exerciseId与练习ID不匹配，期望: "
                        + savedExercise.getExerciseId() + "，实际: " + eqId.getExerciseId());
            }

            // 3. 校验关联的questionId存在于已保存的题目列表中
            if (!savedQuestionIds.contains(eqId.getQuestionId())) {
                throw new IllegalArgumentException("练习-题目关联的questionId不存在于题目列表中，ID: " + eqId.getQuestionId());
            }

            // 4. 设置关联的实体对象（确保JPA正确维护外键关系）
            eq.setExercise(savedExercise); // 关联已保存的练习实体
            Question matchedQuestion = savedQuestions.stream()
                    .filter(q -> q.getQuestionId().equals(eqId.getQuestionId()))
                    .findFirst()
                    .orElseThrow(() -> new IllegalArgumentException("题目未找到，ID: " + eqId.getQuestionId()));
            eq.setQuestion(matchedQuestion); // 关联已保存的题目实体

        }
        exerciseQuestionRepository.saveAll(exerciseQuestions);
    }
    // ExerciseServiceImpl.java
    @Override
    public List<StudentExerciseWithDetailsDTO> getClassExercisesForGrading(String classesId) {
        // 1. 查询班级下的所有练习（通过Classes关联）
        List<Exercise> exercises = exerciseRepository.findByClasses_ClassesId(classesId);

        // 2. 查询每个练习中状态为submitted的学生练习记录
        return exercises.stream()
                .flatMap(exercise -> {
                    List<StudentExercise> studentExercises = studentExerciseRepository.findByExercise_ExerciseIdAndState(
                            exercise.getExerciseId(),
                            "submitted"
                    );
                    return studentExercises.stream().map(se -> mapToDetailsDTO(exercise, se));
                })
                .collect(Collectors.toList());
    }

    private StudentExerciseWithDetailsDTO mapToDetailsDTO(Exercise exercise, StudentExercise se) {
        return new StudentExerciseWithDetailsDTO(
                exercise.getExerciseId(),
                exercise.getExerciseName(),
                se.getUser().getUserId(),
                se.getUser().getUserName(), // 假设User实体有userName字段
                se.getState(),
                se.getStudentScore()
        );
    }

    @Override
    @Transactional // 添加事务注解，确保数据更新
    public ExerciseDetailDTO getStudentExerciseForGrading(String exerciseId, String studentId) {
        // 1. 查询练习详情
        Exercise exercise = exerciseRepository.findById(exerciseId)
                .orElseThrow(() -> new IllegalArgumentException("练习不存在，ID: " + exerciseId));

        // 2. 查询学生练习记录
        StudentExercise studentExercise = studentExerciseRepository.findByUser_UserIdAndExercise_ExerciseId(
                studentId,
                exerciseId
        ).orElseThrow(() -> new IllegalArgumentException("学生未提交此练习，学生ID: " + studentId + "，练习ID: " + exerciseId));

        // 3. 查询学生所有题目答案
        List<StudentQuestionAnswer> studentAnswers = studentQuestionAnswerRepository.findByExercise_ExerciseIdAndUser_UserId(
                exerciseId,
                studentId
        );

        // 4. 通过中间表ExerciseQuestion获取练习关联的题目列表
        List<ExerciseQuestion> exerciseQuestions = exerciseQuestionRepository.findByExercise_ExerciseId(exerciseId);
        List<String> questionIds = exerciseQuestions.stream()
                .map(ExerciseQuestion::getQuestionId) // 使用中间表的getQuestionId方法
                .collect(Collectors.toList());
        List<Question> questions = questionRepository.findAllById(questionIds);

        // 5. 组装题目与答案DTO，并执行自动批改（针对选择题）
        List<QuestionWithAnswerDTO> questionsWithAnswers = questions.stream()
                .map(question -> {
                    StudentQuestionAnswer answer = studentAnswers.stream()
                            .filter(a -> a.getQuestion().getQuestionId().equals(question.getQuestionId()))
                            .findFirst()
                            .orElse(new StudentQuestionAnswer()); // 未找到答案时返回空对象

                    // 自动批改逻辑（假设type为false表示选择题，可根据实际业务调整）
                    if (question.getType() == false) { // 判断是否为选择题（示例条件，需根据实际字段调整）
                        String studentAnswer = answer.getStudentAnswer() != null ? answer.getStudentAnswer() : "";
                        String correctAnswer = question.getQuestionAnswer();
                        long questionScore = question.getQuestionScore();

                        // 对比答案并设置得分
                        if (studentAnswer.equals(correctAnswer)) {
                            answer.setGainScore((int) questionScore); // 设置自动批改得分
                        } else {
                            answer.setGainScore(0);
                        }
                    }
                    return new QuestionWithAnswerDTO(question, answer);
                })
                .collect(Collectors.toList());

        // 6. 计算总分（仅累加选择题得分，其他题型可忽略或自定义逻辑）
        int totalScore = questionsWithAnswers.stream()
                .filter(qwa -> !qwa.getQuestion().getType()) // 过滤选择题
                .mapToInt(qwa -> qwa.getAnswer().getGainScore())
                .sum();

        // 7. 更新学生练习总分并保存（自动批改后立即更新）
        studentExercise.setStudentScore(totalScore);
        studentExerciseRepository.save(studentExercise);

        return new ExerciseDetailDTO(exercise, studentExercise, questionsWithAnswers);
    }


    @Transactional
    @Override
    public void submitGrades(GradeSubmissionDTO gradeSubmission) {
        try {
            // 1. 校验练习和学生存在
            Exercise exercise = exerciseRepository.findById(gradeSubmission.getExerciseId())
                    .orElseThrow(() -> new IllegalArgumentException("练习不存在，ID: " + gradeSubmission.getExerciseId()));
            User student = userRepository.findById(gradeSubmission.getStudentId())
                    .orElseThrow(() -> new IllegalArgumentException("学生不存在，ID: " + gradeSubmission.getStudentId()));

            // 2. 更新学生练习状态和总分
            StudentExercise studentExercise = studentExerciseRepository.findByUser_UserIdAndExercise_ExerciseId(
                    student.getUserId(),
                    exercise.getExerciseId()
            ).orElseThrow(() -> new IllegalArgumentException("学生练习记录不存在"));

            studentExercise.setState("marked");
            studentExercise.setStudentScore(gradeSubmission.getTotalScore());
            studentExerciseRepository.save(studentExercise);

            // 3. 更新题目得分并处理错题库
            gradeSubmission.getGrades().forEach(grade -> {
                StudentQuestionAnswer studentAnswer = studentQuestionAnswerRepository.findById(grade.getId())
                        .orElseThrow(() -> new IllegalArgumentException("题目答案不存在，ID: " + grade.getId()));
                Question question = studentAnswer.getQuestion();

                // 检查题目是否存在（防御性代码）
                if (question == null) {
                    throw new IllegalArgumentException("题目未关联，答案 ID: " + grade.getId());
                }

                studentAnswer.setGainScore(grade.getGainScore());
                studentQuestionAnswerRepository.save(studentAnswer);

                // 添加错题库逻辑（增加空值校验）
                if (grade.getGainScore() < question.getQuestionScore()) {
                    // 确保练习关联了班级和课程
                    if (exercise.getClasses() == null || exercise.getClasses().getCourse() == null) {
                        throw new IllegalArgumentException("练习未关联班级或课程，无法添加错题库");
                    }
                    String courseId = exercise.getClasses().getCourse().getCourseId();
                    addQuestionToWrongBank(student, courseId, question); // 拆分参数，明确课程 ID
                }
            });
        } catch (Exception e) {
            // 记录详细异常日志（生产环境建议使用日志框架，如 Slf4j）
            System.err.println("提交批改失败，原因：" + e.getMessage());
            e.printStackTrace(); // 打印堆栈追踪，便于定位问题
            throw new RuntimeException("提交批改失败，请联系管理员", e); // 抛出自定义异常，包含原始原因
        }
    }

    /**
     * 重构辅助方法，显式传入 courseId，避免空指针
     */
    private void addQuestionToWrongBank(User student, String courseId, Question question) {
        try {
            // 查询或创建错题库（使用显式 courseId）
            WrongQuestionBank wrongBank = wrongQuestionBankRepository.findByUser_UserIdAndCourse_CourseId(
                    student.getUserId(), courseId
            ).orElseGet(() -> {
                String bankId = student.getUserId() + "_" + courseId;
                WrongQuestionBank newBank = new WrongQuestionBank();
                newBank.setWrongQuestionBankId(bankId);
                newBank.setUser(student);
                newBank.setCourse(courseRepository.findById(courseId).orElseThrow(
                        () -> new IllegalArgumentException("课程不存在，ID: " + courseId)
                ));
                return wrongQuestionBankRepository.save(newBank);
            });

            // 避免重复添加
            WrongQuestionBankQuestionId questionBankId = new WrongQuestionBankQuestionId(
                    wrongBank.getWrongQuestionBankId(),
                    question.getQuestionId()
            );
            if (!wrongQuestionBankQuestionRepository.existsById(questionBankId)) {
                WrongQuestionBankQuestion wrongQuestion = new WrongQuestionBankQuestion();
                wrongQuestion.setId(questionBankId);
                wrongQuestion.setWrongQuestionBank(wrongBank);
                wrongQuestion.setQuestion(question);
                wrongQuestionBankQuestionRepository.save(wrongQuestion);
            }
        } catch (Exception e) {
            System.err.println("添加错题库失败，原因：" + e.getMessage());
            throw new RuntimeException("添加错题库失败", e);
        }
    }
    @Transactional
    @Override
    public void deleteExerciseWithCascade(String exerciseId) {
        // 1. 校验练习是否存在
        Exercise exercise = exerciseRepository.findById(exerciseId)
                .orElseThrow(() -> new IllegalArgumentException("练习不存在，ID: " + exerciseId));

        // 2. 删除 student_exercise 表中该练习的所有学生记录
        studentExerciseRepository.deleteByExercise_ExerciseId(exerciseId);

        // 3. 删除 student_question_answer 表中该练习的所有答案记录
        studentQuestionAnswerRepository.deleteByExercise_ExerciseId(exerciseId);

        // 4. 获取该练习关联的所有题目 ID
        List<String> questionIds = exerciseQuestionRepository.findByExercise_ExerciseId(exerciseId)
                .stream()
                .map(ExerciseQuestion::getQuestionId)
                .collect(Collectors.toList());

        // 5. 删除 wrong_question_bank_question 表中涉及这些题目的记录
        if (!questionIds.isEmpty()) {
            wrongQuestionBankQuestionRepository.deleteByQuestion_QuestionIdIn(questionIds);
        }

        // 6. 删除 favorite_question_bank_question 表中涉及这些题目的记录（假设 course_question_bank_question 为收藏表）
        favoriteQuestionBankQuestionRepository.deleteByQuestion_QuestionIdIn(questionIds);

        // 7. 删除 question 表中的题目
        questionRepository.deleteAllById(questionIds);

        // 8. 删除 exercise_question 表中的关联记录（现有逻辑）
        exerciseQuestionRepository.deleteByExercise_ExerciseId(exerciseId);

        // 9. 删除 exercise 表中的练习记录（现有逻辑）
        exerciseRepository.deleteById(exerciseId);
    }
    @Override
    public List<Question> loadCourseQuestionBank(String courseId) {
        // 1. 校验课程存在
        Course course = courseRepository.findById(courseId)
                .orElseThrow(() -> new IllegalArgumentException("课程不存在，ID: " + courseId));

        // 2. 查询或创建课程题库（若不存在则自动创建空题库）
        CourseQuestionBank courseQuestionBank = courseQuestionBankRepository.findByCourse_CourseId(courseId)
                .orElseThrow(() -> new IllegalArgumentException("课程题库不存在，ID: " + courseId));

        // 3. 查询题库关联的所有题目
        List<CourseQuestionBankQuestion> questionRelations = courseQuestionBankQuestionRepository
                .findByCourseQuestionBank_CourseQuestionBankId(courseQuestionBank.getCourseQuestionBankId());

        // 4. 提取题目 ID 并批量查询题目详情
        List<String> questionIds = questionRelations.stream()
                .map(relation -> relation.getQuestion().getQuestionId()) // 直接获取 Question 的 ID
                .collect(Collectors.toList());

        return questionRepository.findAllById(questionIds);
    }

    @Transactional
    @Override
    public Question addQuestionToCourseBank(Question question, String courseId) {
        // 1. 校验课程存在
        Course course = courseRepository.findById(courseId)
                .orElseThrow(() -> new IllegalArgumentException("课程不存在，ID: " + courseId));

        // 2. 获取或创建课程题库
        CourseQuestionBank courseQuestionBank = courseQuestionBankRepository.findByCourse_CourseId(courseId)
                .orElseThrow(() -> new IllegalArgumentException("课程题库不存在，ID: " + courseId));

        // 3. 保存题目（若题目 ID 不存在则自动生成）
        Question savedQuestion;
        if (question.getQuestionId() == null) {
            // 生成唯一题目 ID（示例：Q-时间戳）
            question.setQuestionId("Q-" + System.currentTimeMillis());
            savedQuestion = questionRepository.save(question);
        } else {
            // 检查题目是否已存在
            savedQuestion = questionRepository.findById(question.getQuestionId())
                    .orElse(questionRepository.save(question));
        }

        // 4. 创建题库与题目关联记录
        CourseQuestionBankQuestionId relationId = new CourseQuestionBankQuestionId(
                courseQuestionBank.getCourseQuestionBankId(),
                savedQuestion.getQuestionId()
        );

        // 避免重复添加
        if (!courseQuestionBankQuestionRepository.existsById(relationId)) {
            CourseQuestionBankQuestion relation = new CourseQuestionBankQuestion();
            relation.setId(relationId);
            relation.setCourseQuestionBank(courseQuestionBank);
            relation.setQuestion(savedQuestion);
            courseQuestionBankQuestionRepository.save(relation);
        }

        return savedQuestion;
    }
    @Transactional
    @Override
    public void deleteQuestionFromCourseBank(String questionId, String courseId) {
        // 1. 校验课程存在
        Course course = courseRepository.findById(courseId)
                .orElseThrow(() -> new IllegalArgumentException("课程不存在，ID: " + courseId));

        // 2. 获取课程题库
        CourseQuestionBank courseQuestionBank = courseQuestionBankRepository.findByCourse_CourseId(courseId)
                .orElseThrow(() -> new IllegalArgumentException("课程题库不存在"));

        // 3. 构造关联记录ID
        CourseQuestionBankQuestionId relationId = new CourseQuestionBankQuestionId(
                courseQuestionBank.getCourseQuestionBankId(),
                questionId
        );

        // 4. 查询关联实体（关键修改点）
        CourseQuestionBankQuestion relation = courseQuestionBankQuestionRepository.findById(relationId)
                .orElseThrow(() -> new IllegalArgumentException("题目与题库的关联记录不存在"+relationId+courseQuestionBank.getCourseQuestionBankId()+questionId));

        // 5. 直接删除实体对象（替代原deleteById）
        courseQuestionBankQuestionRepository.delete(relation);
    }
    @Override
    public int calculateStudentRank(StudentExercise studentExercise) {
        // 1. 校验输入参数有效性
        if (studentExercise == null || studentExercise.getId() == null) {
            throw new IllegalArgumentException("学生练习记录不能为空");
        }

        StudentExerciseId id = studentExercise.getId();
        if (id.getExerciseId() == null || id.getUserId() == null) {
            throw new IllegalArgumentException("练习ID或学生ID不能为空");
        }

        Integer studentScore = studentExercise.getStudentScore();
        if (studentScore == null || studentScore < 0) {
            throw new IllegalArgumentException("学生得分无效");
        }

        // 2. 查询该练习下的所有学生练习记录
        List<StudentExercise> allStudentExercises = studentExerciseRepository.findByExercise_ExerciseId(id.getExerciseId());

        // 3. 过滤有效得分（排除未提交/无得分的记录）
        List<Integer> validScores = allStudentExercises.stream()
                .map(StudentExercise::getStudentScore)
                .filter(Objects::nonNull)
                .filter(score -> score >= 0)
                .collect(Collectors.toList());

        // 4. 处理无有效得分的情况
        if (validScores.isEmpty()) {
            return 1; // 只有自己时排名为1
        }

        // 5. 降序排序分数
        validScores.sort(Comparator.reverseOrder());

        // 6. 计算排名（相同分数按出现顺序排名，非并列排名）
        int rank = 1;
        for (Integer score : validScores) {
            if (score > studentScore) {
                rank++;
            } else if (score.equals(studentScore)) {
                // 找到第一个等于当前分数的位置，返回当前排名
                return rank;
            }
        }

        // 如果当前分数小于所有有效分数（排名最后）
        return validScores.contains(studentScore) ? rank : validScores.size() + 1;
    }
    // ====================== 新增函数 1：根据课程ID和用户ID获取班级ID ======================
    @Override
    public String getClassesIdByCourseAndUser(String courseId, String userId) {
        // 1. 查询课程下的所有班级
        List<Classes> classesList = classesRepository.findByCourseCourseId(courseId);
        if (classesList.isEmpty()) {
            throw new IllegalArgumentException("课程下无班级，课程ID: " + courseId);
        }

        // 2. 提取班级ID列表
        List<String> classIds = classesList.stream()
                .map(Classes::getClassesId)
                .collect(Collectors.toList());

        // 3. 检查用户是否属于任一班级（学生或教师）
        return classIds.stream()
                .filter(classId -> isUserInClass(classId, userId))
                .findFirst() // 取第一个匹配的班级ID
                .orElse(null); // 无匹配则返回null
    }

    // ====================== 新增函数 2：根据课程ID和用户ID获取身份 ======================
    @Override
    public String getUserRoleByCourseAndUser(String courseId, String userId) {
        // 学生身份查询（正确使用复合主键）
        if (courseStudentRepository.existsByCourseIdAndUserId(courseId,userId)) {
            return "student";
        }

        // 教师身份查询（通过显式 JPQL 避免自动解析错误）
        if (courseTeacherRepository.existsByCourseIdAndUserId(courseId, userId)) {
            return "teacher";
        }

        return "undefined";
    }


    // ====================== 辅助方法：检查用户是否属于班级（学生或教师） ======================
    private boolean isUserInClass(String classId, String userId) {
        return isStudentInClass(classId, userId) || isTeacherInClass(classId, userId);
    }

    private boolean isStudentInClass(String classId, String userId) {
        ClassesStudentId studentId = new ClassesStudentId(userId, classId);
        return classesStudentRepository.existsById(studentId);
    }

    private boolean isTeacherInClass(String classId, String userId) {
        ClassesTeacherId teacherId = new ClassesTeacherId(userId, classId);
        return classesTeacherRepository.existsById(teacherId);
    }
    @Override
    public List<Exercise> getClassExercises(String classId) {
        // 根据班级id返回班级下所有课程
        return exerciseRepository.findByClassesIdIn(Collections.singletonList(classId));
    }
    /**
     * 根据课程ID和用户ID查询该用户作为教师的所有班级
     * @param courseId 课程ID
     * @param userId 用户ID
     * @return 符合条件的班级列表
     */
    @Override
    public List<Classes> getClassesAsTeacher(String courseId, String userId) {
        // 1. 查询课程下的所有班级
        List<Classes> allClasses = classesRepository.findByCourseCourseId(courseId);

        // 2. 过滤出用户作为教师的班级
        return allClasses.stream()
                .filter(classes -> isUserTeacherOfClass(classes, userId))
                .collect(Collectors.toList());
    }

    /**
     * 检查用户是否为某个班级的教师
     * @param classes 班级实体
     * @param userId 用户ID
     * @return 是否为教师
     */
    public boolean isUserTeacherOfClass(Classes classes, String userId) {
        // 创建复合主键对象
        ClassesTeacherId teacherId = new ClassesTeacherId(userId, classes.getClassesId());

        // 查询关联表是否存在记录
        return classesTeacherRepository.existsById(teacherId);
    }
}
